import json
import logging
from decimal import Decimal
from django.utils import timezone

from django import http
from django.db import transaction
from django.shortcuts import render
from django_redis  import get_redis_connection
from meiduo_mall.utils.views import LoginRequired
from orders.models import OrderInfo, OrderGoods
from users.models import Address
from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE

logger = logging.getLogger('django')

class OrderSettlementView(LoginRequired):
    # 结算订单展示界面
    def get(self, request):
        # 提供结算订单
        # 获取登陆用户
        user = request.user
        # 查询地址
        addresses = Address.objects.filter(user=user, is_deleted=False)
        # 从Redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')
        # 找出carts和selected
        redis_carts = redis_conn.hgetall('carts_%s' % user.id)
        redis_selected = redis_conn.smembers('selected_%s' % user.id)
        # 对hash数据过滤只要selected勾选的
        cart_dict = {}
        for sku_id_bytes in redis_selected:
            cart_dict[int(sku_id_bytes)] = int(redis_carts[sku_id_bytes])
        # 通过sku_id查询到所有sku模型
        skus = SKU.objects.filter(id__in=cart_dict.keys())
        # 准备初始值
        total_count = 0
        total_amount = 0
        # 遍历sku查询 模型给每个sku模型多定义一个count和amount属性
        for sku in skus:
            sku.count = cart_dict[sku.id]
            sku.amount = sku.price * sku.count

            total_count += sku.count
            total_amount += sku.amount
        freight = Decimal(10.00)

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
        }
        return render(request, 'place_order.html', context)


class OrderCommitView(LoginRequired):
    def post(self, request):
        # 1.接收请求体数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        user = request.user
        # 2.校验
        if all([address_id, pay_method]) is False:
            return http.HttpResponseForbidden('缺少必传参数')
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数有误')
        try:
            address = Address.objects.get(id=address_id, is_deleted=False, user=user)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('address_id无效')
        # 生成订单编号:  2019071912212   + 000000001
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id
        # 判断订单状态
        status = (OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                  if (pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'])
                  else OrderInfo.ORDER_STATUS_ENUM['UNSEND'])

        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                # 一. 新增订单基本信息记录
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=status,
                )
                # 创建redis连接
                redis_conn = get_redis_connection('carts')
                # 获取hash数据
                redis_carts = redis_conn.hgetall('carts_%s' % user.id)
                # 获取set数据
                redis_selected = redis_conn.smembers('selected_%s' % user.id)
                # 定义字典用来装所有要购买商品id和count
                carts_dict = {}
                # 对redis 中hash购物车数据进行过滤,只要勾选的数据
                for sku_bytes_id in redis_selected:
                    carts_dict[int(sku_bytes_id)] = int(redis_carts[sku_bytes_id])
                # 遍历要购买商品数据字典
                for sku_id in carts_dict:
                    while True:
                        # 查询sku模型
                        sku = SKU.objects.get(id=sku_id)
                        # 获取当前商品要购买的数量
                        buy_count = carts_dict[sku_id]
                        # 获取当前sku原本的库存
                        origin_stock = sku.stock
                        # 获取当前sku原本销量
                        origin_sales = sku.sales
                        # 判断库存
                        if buy_count > origin_stock:
                            # 如果库存不足对事务的操作进行回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                        # 二. 修改sku的库存和销量
                        # 计算新的库存
                        new_stock = origin_stock - buy_count
                        # 计算新的销量
                        new_sales = origin_sales + buy_count
                        # 给sku的库存和销量属性重新赋值
                        # sku.stock = new_stock
                        # sku.sales = new_sales
                        # sku.save()
                        # 进行乐观锁的操作为了防止
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if result == 0:
                            continue

                        # 三. 修改spu销量
                        spu = sku.spu
                        spu.sales += buy_count
                        spu.save()
                        # 四. 新增订单中N个商品记录
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=buy_count,
                            price=sku.price,
                        )
                        # 累加订单中商品总数量
                        order.total_count += buy_count
                        order.total_amount += (sku.price * buy_count)
                        break
                # 累加运费一定要写在for的外面
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '提交订单失败'})
            else:
                transaction.savepoint_commit(save_id)
        # 清除购物车中已购买过的商品
        try:
            pl = redis_conn.pipeline()
            pl.hdel('carts_%s', user.id, *carts_dict.keys())
            pl.delete('selected_%s' % user.id)
            pl.execute()
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '购物车数据有误'})
        # 响应
        return http.JsonResponse({'code': RETCODE.DBERR , 'errmsg': 'OK', 'order_id': order_id})


class OrderSuccessView(LoginRequired):
    def get(self, request):
        # 接收参数
        query_dict = request.GET
        payment_amount = query_dict.get('payment_amount')
        order_id = query_dict.get('order_id')
        pay_method = query_dict.get('pay_method')
        # 校验
        try:
            OrderInfo.objects.filter(total_amount=payment_amount, order_id=order_id, pay_method=pay_method, user=request.user)
        except OrderInfo.DoesNotExist:
            return http.HttpResponseForbidden('订单有误')
        # 渲染数据
        context = {
            'payment_amount': payment_amount,
            'order_id': order_id,
            'pay_method': pay_method,
        }
        # 响应
        return render(request, 'order_success.html', context)


class AllOrderView(LoginRequired):
    """用户中心全部订单显示"""

    def get(self, request):
        # 获取登录用户
        user = request.user
        # 取到该用户的所有订单
        order_qs = OrderInfo.objects.filter(user_id=user.id)
        # 渲染页面需要的全部数据
        page_orders = []
        # 遍历获取单个订单
        for order in order_qs:
            # 取到该订单的所有商品
            sku_qs = OrderGoods.objects.filter(order_id=order.order_id)
            # 商品信息列表
            sku_list = []
            # 遍历获取单个订单商品
            for sku_good in sku_qs:
                # sku = SKU.objects.get(id=sku_good.sku_id)
                # 取到该订单商品的信息
                sku = sku_good.sku
                sku_list.append({
                    "default_image": sku.default_image.url,
                    "name": sku.name,
                    "count": sku_good.count,
                    "price": str(sku_good.price),
                    "amount": str(sku_good.price * sku_good.count)
                })
            page_orders.append({
                "create_time": order.create_time,
                "order_id": order.order_id,
                "sku_list": sku_list,
                "total_amount": order.total_amount + order.freight,
                "freight": order.freight,
                "pay_method_name": order.get_pay_method_display(),
                "status": order.status,
                # "status":4,
                "status_name": order.get_status_display()
                # "status_name":"待评价"
            })

        # 渲染数据
        context = {"page_orders": page_orders}

        return render(request, "user_center_order.html", context)


class OrderCommentView(LoginRequired):
    """商品评论提交"""

    def get(self, request):
        """渲染评论页面"""
        user = request.user
        # 获取订单编号
        order_id = request.GET.get("order_id")
        sku_qs = OrderGoods.objects.filter(order_id=order_id, is_commented=False)
        # sku_qs = OrderGoods.objects.filter(order_id=order_id,status=4,is_commented=False)
        uncomment_goods_list = []
        for sku_good in sku_qs:
            # sku = SKU.objects.get(id=sku_good.sku_id)
            sku = sku_good.sku
            uncomment_goods_list.append({
                "order_id": order_id,
                "sku_id": sku.id,
                "url": '/detail/' + str(sku_good.sku_id) + '/',
                "default_image_url": sku.default_image.url,
                "name": sku.name,
                "price": str(sku_good.price),
                # "score": 0,
                # "final_score":0,
                # "display_score": 0,
                # "comment": sku_good.comment,
                # "is_anonymous": sku_good.is_anonymous

            })
        context = {"uncomment_goods_list": uncomment_goods_list}
        return render(request, "goods_judge.html", context)

    def post(self, request):
        """提交订单"""
        # 获取数据
        json_dict = json.loads(request.body.decode())
        order_id = json_dict.get("order_id")
        sku_id = json_dict.get("sku_id")
        comment = json_dict.get("comment")
        score = json_dict.get("score")
        is_anonymous = json_dict.get("is_anonymous")
        # 校验
        if not all([order_id, sku_id, comment, score]):
            return http.HttpResponseForbidden("缺少参数")
        if len(comment) < 5:
            return http.HttpResponseForbidden("请填写多于5个字的评价内容")
        order = OrderInfo.objects.get(order_id=order_id)
        goods_qs = OrderGoods.objects.filter(order_id=order_id)
        sku = SKU.objects.get(id=sku_id)
        order_good = OrderGoods.objects.get(order_id=order_id, sku_id=sku_id)
        if order_good.is_commented:
            return http.HttpResponseForbidden("订单商品已评论")
        # 提交数据库保存
        order_good.comment = comment
        order_good.score = score
        order_good.is_anonymous = is_anonymous
        order_good.is_commented = True
        order_good.save()
        sku.comments += 1
        sku.save()
        # 遍历订单中所有的商品，当所有商品都已评论才将订单状态改为已完成
        for good in goods_qs:
            if good.is_commented == False:
                break
        else:
            order.status = 5
            order.save()
        # 响应
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "评价提交成功"})




